package groep1.graph.graphstrategy.line;

import java.awt.Point;

/**
 * A subclass of the line class which only allows straight lines to be drawn.
 * 
 * @author Niels Billen
 * @version 0.1
 * @since 0.1
 */
public class RectangularLine extends Line {
	/**
	 * Creates a new straight line from the given points.
	 * 
	 * @param points
	 *            The points of the line.
	 * @throws NullPointerException
	 *             When the given points are null.
	 * @throws IllegalArgumentException
	 *             When the given points do not lay on one line.
	 */
	public RectangularLine(Point... points) throws NullPointerException,
			IllegalArgumentException {
		super(points);
	}

	/**
	 * Creates a new straight line from the given points.
	 * 
	 * @param line
	 *            The line to create this line from.
	 * @throws NullPointerException
	 *             When the given line is null.
	 */
	public RectangularLine(RectangularLine line) throws NullPointerException {
		super(line);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see groep1.graph.graphstrategy.line.Line#addPoint(java.awt.Point)
	 */
	@Override
	public void addPoint(Point point) throws NullPointerException,
			IllegalArgumentException {
		if (getNbOfPoints() == 0) {
			super.addPoint(point);
			return;
		}
		if (point == null)
			throw new NullPointerException("The given point is null!");

		Point lastPoint = getLastPoint();

		if (point.getX() == lastPoint.getX()
				|| point.getY() == lastPoint.getY())
			super.addPoint(point);
		else
			throw new IllegalArgumentException(
					"The given point does not form a straight line!");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see groep1.graph.graphstrategy.line.Line#overlap(java.awt.Point)
	 */
	@Override
	public boolean overlap(Point point) {
		if (getNbOfPoints() < 2)
			return false;
		Point a;
		Point b;
		LineSegment line;
		for (int i = 1; i < getNbOfPoints(); i++) {
			a = getPointAt(i);
			b = getPointAt(i - 1);
			line = new LineSegment(a, b);

			if (line.isHorizontal()) {
				if (point.y == a.y) {
					int minX = Math.min(a.x, b.x);
					int maxX = Math.max(a.x, b.x);

					if (point.x >= minX && point.x <= maxX)
						return true;
				}
			} else if (line.isVertical()) {
				if (point.x == a.x) {
					int minY = Math.min(a.y, b.y);
					int maxY = Math.max(a.y, b.y);

					if (point.y >= minY && point.y <= maxY)
						return true;
				}
			}
		}

		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * groep1.graph.graphstrategy.line.Line#overlap(groep1.graph.graphstrategy
	 * .line.Line)
	 */
	@Override
	public boolean overlap(Line line) {
		if (!(line instanceof RectangularLine))
			return false;
		if (getNbOfPoints() < 2)
			return false;
		if (line.getNbOfPoints() < 2)
			return false;

		RectangularLine l = (RectangularLine) line;
		Point thisA;
		Point thisB;
		Point otherA;
		Point otherB;
		LineSegment thisLine;
		LineSegment otherLine;

		for (int i = 0; i < getNbOfPoints() - 1; i++) {
			thisA = getPointAt(i);
			thisB = getPointAt(i + 1);
			thisLine = new LineSegment(thisA, thisB);

			for (int k = 0; k < line.getNbOfPoints() - 1; k++) {
				otherA = l.getPointAt(k);
				otherB = l.getPointAt(k + 1);
				otherLine = new LineSegment(otherA, otherB);

				if (thisLine.isHorizontal() && otherLine.isHorizontal()) {
					if (thisA.y == otherA.y) {
						int thisMinX = Math.min(thisA.x, thisB.x);
						int thisMaxX = Math.max(thisA.x, thisB.x);
						int otherMinX = Math.min(otherA.x, otherB.x);
						int otherMaxX = Math.max(otherA.x, otherB.x);

						if (otherMinX > thisMaxX)
							continue;
						if (otherMaxX < thisMinX)
							continue;
						return true;

					}
				} else if (thisLine.isVertical() && otherLine.isVertical()) {
					if (thisA.x == otherA.x) {
						int thisMinY = Math.min(thisA.y, thisB.y);
						int thisMaxY = Math.max(thisA.y, thisB.y);
						int otherMinY = Math.min(otherA.y, otherB.y);
						int otherMaxY = Math.max(otherA.y, otherB.y);

						if (otherMinY > thisMaxY)
							continue;
						if (otherMaxY < thisMinY)
							continue;
						return true;

					}
				}
			}
		}
		return false;

	}

//	/*
//	 * (non-Javadoc)
//	 * 
//	 * @see
//	 * groep1.graph.graphstrategy.line.Line#overlap(groep1.graph.GraphObject,
//	 * int)
//	 */
//	@Override
//	public boolean overlap(GraphObject object, int offSet) {
//		Point p1;
//		Point p2;
//		LineSegment line;
//
//		if (getNbOfPoints() < 2)
//			return false;
//
//		int minX;
//		int minY;
//		int maxX;
//		int maxY;
//
//		for (int i = 1; i < getNbOfPoints(); i++) {
//			p1 = getPointAt(i - 1);
//			p2 = getPointAt(i);
//			line = new LineSegment(p1, p2);
//
//			if (line.isHorizontal()) {
//				minX = Math.min(p1.x, p2.x);
//				maxX = Math.max(p1.x, p2.x);
//				
//				if (maxX<object.getPosition().x)
//				if (p1.y >= object.getPosition().y - offSet
//						&& p1.y <= object.getPosition().y + object.getHeight()
//								+ offSet)
//					return true;
//
//			} else if (line.isVertical()) {
//				if (p1.x >= object.getPosition().x - offSet
//						&& p1.x <= object.getPosition().x + object.getWidth()
//								+ offSet)
//					return true;
//			}
//		}
//
//		return false;
//	}

	/**
	 * An internal class representing a line segment.
	 * 
	 * @author Niels Billen, Jorn Van Loock.
	 * @version 0.1
	 * @since 0.1
	 */
	private class LineSegment {
		/**
		 * Creates a new line segment from the given points.
		 * 
		 * @param pointA
		 *            The first point of the line segment.
		 * @param pointB
		 *            The second point of the line segment.
		 * @throws NullPointerException
		 */
		public LineSegment(Point pointA, Point pointB)
				throws NullPointerException {
			this.pointA = pointA;
			this.pointB = pointB;

		}

		/**
		 * Returns whether the line segment is horizontal.
		 * 
		 * @return whether the line segment is horizontal.
		 */
		public boolean isHorizontal() {
			return pointA.getY() == pointB.getY();
		}

		/**
		 * Returns whether the line segment is vertical.
		 * 
		 * @return whether the line segment is vertical.
		 */
		public boolean isVertical() {
			return pointA.getX() == pointB.getX();
		}

		/**
		 * The first point of the line segment.
		 */
		private Point pointA;

		/**
		 * The second point of the line segment.
		 */
		private Point pointB;
	}
}
